package com.daisuxia.web.service;



import java.net.InetAddress;
import java.net.UnknownHostException;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.daisuxia.web.util.IPv4Util;

/**
 * 
 * @author Administrator
 *
 */
@Transactional
@Service
public class SequenceManagerServiceImpl implements SequenceManagerService {

	// 序列号更新时的最大重试次数
	private static final int RETRY_LIMIT = 100;

	// 错误CODE
	private static final String ERR_CUSTOM = "ERR_CUSTOM";

	//@Autowired
	private static final Long workerId = 1L;
	//@Autowired
	private static final Long datacenterId = 3L;

	private long sequence = 0L;

	private final long workerIdBits = 5L;
	private final long datacenterIdBits = 5L;
	private long maxWorkerId = ~(-1L << workerIdBits);
	private long maxDatacenterId = ~(-1L << datacenterIdBits);
	private final long sequenceBits = 12L;

	private final long workerIdShift = sequenceBits;
	private final long datacenterIdShift = sequenceBits + workerIdBits;
	private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
	private final long sequenceMask = ~(-1L << sequenceBits);

	private long lastTimestamp = -1L;

	@Transactional(readOnly = true)
	public synchronized Long getNewId() {
		//        workerId = 1L;
		//        datacenterId = 3L;

		long timestamp = timeGen();

		if (timestamp < lastTimestamp) {
			// 时序倒转时报错，理论上不可能发生
			throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
		}

		if (lastTimestamp == timestamp) {
			sequence = (sequence + 1) & sequenceMask;
			if (sequence == 0) {
				// 如果本毫秒内执行超过限定次数，则等待到下一毫秒继续执行，理论上不可能发生
				timestamp = tilNextMillis(lastTimestamp);
			}
		} else {
			sequence = 0L;
		}

		lastTimestamp = timestamp;
        //防止多个服务器产生相同的序列号，加上本机IP地址做标识符
		long twepoch = Math.abs(IPv4Util.ipToLong(getLocalHostIp()));
		return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
	}

	protected long tilNextMillis(long lastTimestamp) {
		// 如果本毫秒内执行超过限定次数，则等待到下一毫秒继续执行，理论上不可能执行本方法
		long timestamp = timeGen();
		while (timestamp <= lastTimestamp) {
			timestamp = timeGen();
		}
		return timestamp;
	}

	protected long timeGen() {
		return System.currentTimeMillis();
	}
	/**
	 * 获取本机的IP地址
	 * @author zhangsh Tel:13817876783
	 * @date 2017年9月25日 上午10:28:58
	 * @Title getLocalHostIp
	 * @Description 
	 * @return String 
	 * @throws
	 */
	protected String  getLocalHostIp() {
		String ip="";
		 try {
			ip= InetAddress.getLocalHost().getHostAddress();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return ip;
	}
	
	public static void main(String[] args) {
		System.out.println(new SequenceManagerServiceImpl().getNewId());
	}
}
